home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-03 | 22.8 KB | 788 lines | [TEXT/MPS ] |
- //----------------------------------------------------------------------------------------
- // UDynamicArray.cp
- // Copyright © 1986-96 by Apple Computer, Inc. All rights reserved.
- //----------------------------------------------------------------------------------------
-
- #ifndef __UDYNAMICARRAY__
- #include "UDynamicArray.h"
- #endif
-
- // MacApp
-
- #ifndef __UFAILURE__
- #include "UFailure.h"
- #endif
-
- #ifndef __ULISTITERATOR__
- #include "UListIterator.h"
- #endif
-
- #ifndef __UCOREUTILITIES__
- #include "UCoreUtilities.h"
- #endif
-
- #ifndef __UMEMORY__
- #include "UMemory.h"
- #endif
-
- #ifndef __USTREAM__
- #include "UStream.h"
- #endif
-
-
- // OpenDoc
-
- #ifndef _MEMMGR_
- #include "MemMgr.h"
- #endif
-
-
- // Toolbox
-
- #ifndef __PACKAGES__
- #include <Packages.h>
- #endif
-
- // ANSI
-
- #ifndef __STDIO__
- #include <stdio.h>
- #endif
-
- #ifndef __STDLIB__
- #include <stdlib.h>
- #endif
-
-
- //========================================================================================
- // GLOBAL Procedures
- //========================================================================================
- static CompareResult TestItemForInsert(ArrayIndex anItem,
- void* yourDataPtr);
-
- static CompareResult CompareElements(void* element1,
- void* element2,
- void* yourDataPtr);
-
- static ArrayIndex RandomArrayIndex(ArrayIndex beginIndex,
- ArrayIndex endIndex);
-
- //========================================================================================
- // CLASS TDynamicArray
- //========================================================================================
- #undef Inherited
- #define Inherited TObject
-
- #pragma segment ListNonRes
- MA_DEFINE_CLASS_M1(TDynamicArray,
- Inherited);
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray constructor
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- TDynamicArray::TDynamicArray() :
- fIteratorPtr(NULL),
-
- fAllocatedSize(kEmptyIndex),
- fAllocationIncrement(kAllocationIncrement),
- fElementSize(1),
- fElementSizeShift(0),
- fFreeRequested(FALSE),
- fSize(kEmptyIndex),
- fArraySpace(NULL)
- {
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray destructor
- //----------------------------------------------------------------------------------------
- #pragma segment MADestructorRes
-
- TDynamicArray::~TDynamicArray()
- {
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::IDynamicArray:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::IDynamicArray(ArrayIndex initialSize,
- short elementSize)
- {
- IObject();
-
- #if qDebug
- if (initialSize < kEmptyIndex)
- {
- ProgramBreak("initialSize must be non-negative!");
- initialSize = kEmptyIndex;
- }
-
- if (elementSize <= 0)
- {
- ProgramBreak("In TDynamicArray.IDynamicArray: preposterous element size. (zero or negative)");
- Failure(minErr, 0);
- }
- #endif
-
- fSize = kEmptyIndex;
-
- fElementSize = elementSize;
- fAllocatedSize = kEmptyIndex;
-
- // calculate the elementsizeshift that represents the nearest power of 2
- fElementSizeShift = 0;
- while (((elementSize - 1) >> fElementSizeShift) > 0)
- ++fElementSizeShift;
-
- FailInfo fi;
- Try(fi)
- {
- SetArraySize(initialSize);
- fi.Success();
- }
- else
- {
- Free();
- fi.ReSignal();
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::Clone:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- TObject* TDynamicArray::Clone()
- {
- MAVolatileInit(TDynamicArray * , aClonedDynamicArray, (TDynamicArray *)(Inherited::Clone()));
-
- aClonedDynamicArray->fIteratorPtr = NULL;
- aClonedDynamicArray->fArraySpace = NULL;
-
- FailInfo fi;
- Try(fi)
- {
- long itsSize = (long)MMBlockSize(fArraySpace);
- Ptr newVal = (Ptr)new
- char[itsSize];
-
- MABlockMove(fArraySpace, newVal, itsSize);
-
- aClonedDynamicArray->fArraySpace = newVal;
- fi.Success();
- }
- else
- {
- aClonedDynamicArray->Free();
-
- fi.ReSignal();
- }
-
- return aClonedDynamicArray;
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::ReadFrom:
- //----------------------------------------------------------------------------------------
- #pragma segment MAReadResource
-
- void TDynamicArray::ReadFrom(TStream* aStream)
- {
- Inherited::ReadFrom(aStream);
-
- fElementSize = aStream->ReadInteger();
- fElementSizeShift = aStream->ReadInteger();
- fAllocationIncrement = aStream->ReadLong();
-
- FailInfo fi;
- Try(fi)
- {
- SetArraySize(0);
- fi.Success();
- }
- else
- {
- Free();
- fi.ReSignal();
- }
-
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::WriteTo:
- //----------------------------------------------------------------------------------------
- #pragma segment MAWriteResource
-
- void TDynamicArray::WriteTo(TStream* aStream)
- {
- Inherited::WriteTo(aStream);
-
- aStream->WriteInteger(fElementSize);
- aStream->WriteInteger(fElementSizeShift);
- aStream->WriteLong(fAllocationIncrement);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::operator[]:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void* TDynamicArray::operator[](ArrayIndex index) const
- {
- return fArraySpace + (index << fElementSizeShift);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::ComputeAddress:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void* TDynamicArray::ComputeAddress(ArrayIndex index) const
- {
- return fArraySpace + ((index - 1) << fElementSizeShift);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::DeleteElementsAt:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::DeleteElementsAt(ArrayIndex index,
- ArrayIndex count)
- {
- #if qRangeCheck
- if ((index < 1) || (index > fSize))
- {
- #if qDebugMsg
- fprintf(stderr, "fSize == %1d index == %1d\n", fSize, index);
- #endif
-
- ProgramBreak("Range Check in TDynamicArray.DeleteElementsAt");
- }
- #endif
-
- ArrayIndex countBytes = count << fElementSizeShift;
-
- void* indexPtr = ComputeAddress(index);
- void* nextElementPtr = ComputeAddress(index + count);
- void* lastElementPtr = ComputeAddress(fSize + 1);
-
- if (nextElementPtr < lastElementPtr) // deleted from middle? Compress the array
- MABlockMoveOverlap(nextElementPtr, indexPtr, (long)lastElementPtr - (long)nextElementPtr);
-
- #if qDebug
- BlockSet((Ptr)((long)lastElementPtr - countBytes), countBytes, kResizedInitVal);
- #endif
-
- SetArraySize(fSize - count); // take up slack if necessary. Should never
- // Fail when shrinking array.
- fSize -= count;
-
- if (fIteratorPtr) // Keep all iterations apprised
- fIteratorPtr->DeleteElementAt(index, count);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::DeleteAll:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::DeleteAll()
- {
- if (fSize)
- DeleteElementsAt(1, fSize);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::GetElementsAt:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::GetElementsAt(ArrayIndex index,
- void* ElementPtr,
- ArrayIndex count)
- {
- #if qRangeCheck
- if ((index < 1) || (index > fSize))
- {
- #if qDebugMsg
- fprintf(stderr, "fSize == %1d index == %1d\n", fSize, index);
- #endif
-
- ProgramBreak("Range Check in TDynamicArray::GetElementsAt");
- }
- #endif
-
- // The count computation for this move makes sure that if the element size is not
- // a power of 2 that we don't copy more bytes back to the caller than required for a
- // given number of elements sending the caller into orbit and heading straight for the
- // Excedrin.
-
- // !!! NOTE MULTIPLE (> 1) element moves for non-power of 2 element sizes are not yet
- // supported!
-
- if (count > kEmptyIndex)
- MABlockMove(ComputeAddress(index), (Ptr)ElementPtr, ((count - 1) << fElementSizeShift) + fElementSize);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::Free:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::Free()
- {
- // She can't do it cap'n. The dilithium crystals are burrrrnt out! If they're
- // allowed to rest a while they might recover enough for another try.
- if (fIteratorPtr)
- {
- fFreeRequested = TRUE;
- DeleteAll();
- }
- else
- {
- delete fArraySpace;
- fArraySpace = NULL;
-
- Inherited::Free();
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::InsertElementsBefore:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::InsertElementsBefore(ArrayIndex index,
- const void* ElementPtr,
- ArrayIndex count)
- {
- #if qRangeCheck
- if ((index < 1) || (index > fSize + 1))
- {
- #if qDebugMsg
- fprintf(stderr, "fSize == %1d index == %1d\n", fSize, index);
- #endif
-
- ProgramBreak("Range Check in TDynamicArray.InsertElementsBefore");
- }
- #endif
-
- if (fSize + count > fAllocatedSize)
- SetArraySize(fSize + count); // make sure there's room if needed
-
- ArrayIndex countBytes = count << fElementSizeShift;
-
- void* indexPtr = ComputeAddress(index);
- void* nextIndexPtr = ComputeAddress(index + count);
- void* lastElementPtr = ComputeAddress(fSize + 1);
-
- if (index <= fSize) // clear out a hole?
- MABlockMoveOverlap(indexPtr, nextIndexPtr, (long)lastElementPtr - (long)indexPtr);
-
- // !!! we still don't account for multiple element moves with non power of 2 element sizes.
- // Would it be best to create a MoveElements method and put the smarts in it?
-
- if ((countBytes == sizeof(long)) && !odd((Ptr)ElementPtr) && !odd(indexPtr))
- *((long*)indexPtr) = *((long*)ElementPtr);// shortcut for longs
- else
- MABlockMove((Ptr)ElementPtr, indexPtr, countBytes);// longcut for shorts (and other sizes)
-
- fSize += count;
-
- if (fIteratorPtr) // Keep all iterations apprised
- fIteratorPtr->InsertElementBefore(index, count);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::Merge:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::Merge(TDynamicArray* aDynamicArray)
- {
- #if qDebug
- if ((fElementSize != aDynamicArray->fElementSize) || (fElementSizeShift != aDynamicArray->fElementSizeShift))
- ProgramBreak("In TDynamicArray.Merge: fElementSize or fElementSizeShift don't match with the TDynamicArray to merge!");
- #endif
-
- ArrayIndex arraySize = aDynamicArray->GetSize();
- if (arraySize != kEmptyIndex)
- {
- // Force the memory move before the call to ComputeAddress.
- SetArraySize(GetSize() + arraySize);
- InsertElementsBefore(GetSize() + 1, aDynamicArray->ComputeAddress(1), arraySize);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::ReplaceElementsAt:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::ReplaceElementsAt(ArrayIndex index,
- const void* ElementPtr,
- ArrayIndex count)
- {
- #if qRangeCheck
- if ((index < 1) || (index > fSize))
- {
- #if qDebugMsg
- fprintf(stderr, "fSize == %1d index == %1d\n", fSize, index);
- #endif
-
- ProgramBreak("Range Check in TDynamicArray.ReplaceElementsAt");
- }
- #endif
-
- MABlockMove((Ptr)ElementPtr, ComputeAddress(index), count << fElementSizeShift);
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::SetArraySize:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::SetArraySize(ArrayIndex theSize)
- {
- ArrayIndex newAllocatedSize;
-
- if (fArraySpace == NULL)
- fArraySpace = new char[0];
-
- if ((theSize > fAllocatedSize) || (fAllocatedSize - theSize >= fAllocationIncrement))
- {
- #if qDebug
- if (fAllocationIncrement < 0)
- ProgramBreak("fAllocationIncrement < 0 ! You have serious problems.");
- #endif
-
- // Set the # of allocated elements to the nearest multiple of
- // fAllocationIncrement.
- if (fAllocationIncrement)
- newAllocatedSize = (theSize + fAllocationIncrement) - (theSize + fAllocationIncrement) % fAllocationIncrement;
- else
- newAllocatedSize = theSize;
-
- if (newAllocatedSize != fAllocatedSize)
- {
- Ptr newPtr = (Ptr)MMReallocate(fArraySpace, (newAllocatedSize << fElementSizeShift));
- if (newPtr == fArraySpace) // was not reallocated!
- Failure(memFullErr, 0);
- else
- fArraySpace = newPtr;
- }
-
- fAllocatedSize = newAllocatedSize;
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::CompareElements:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- CompareResult TDynamicArray::CompareElements(void* /* Element1 */, void* /* Element2 */)
- {
- // By Default consider all items equal
- return kItem1EqualItem2;
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::Sort:
- //----------------------------------------------------------------------------------------
- void TDynamicArray::Sort()
- {
- if (GetSize() > 0)
- {
- void* swapBuffer = GetSwapBuffer();
- QuickSort(1, fSize, &::CompareElements, this, swapBuffer);
- ReleaseSwapBuffer(swapBuffer);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::SortBy: NOTE: This doesn't work with a CompareItems Function that inserts
- // or deletes elements.
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- void TDynamicArray::SortElementsBy(CompareElementsType CompareItems,
- void* yourDataPtr)
- {
- if (GetSize() > 0)
- {
- void* swapBuffer = GetSwapBuffer();
- QuickSort(1, fSize, CompareItems, yourDataPtr, swapBuffer);
- ReleaseSwapBuffer(swapBuffer);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QuickSort:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- void* TDynamicArray::GetSwapBuffer()
- {
- return (fElementSize == sizeof(long)) ? NULL : (void*) new char[fElementSize];
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QuickSort:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- void TDynamicArray::ReleaseSwapBuffer(void* swapBuffer)
- {
- if (fElementSize == sizeof(long))
- delete swapBuffer;
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QuickSort:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- void TDynamicArray::SwapElements(void* element1, void* element2, void* swapBuffer)
- {
- if (fElementSize == sizeof(long)) // shortcut for longs
- {
- register long swapLong = *(long*)element1;
- *(long*)element1 = *(long*)element2;
- *(long*)element2 = swapLong;
- }
- else
- {
- MABlockMove(element1, swapBuffer, fElementSize);
- MABlockMove(element2, element1, fElementSize);
- MABlockMove(swapBuffer, element2, fElementSize);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QuickSort:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- void TDynamicArray::QuickSort(ArrayIndex beginIndex,
- // p
- ArrayIndex endIndex,
- // r
- CompareElementsType CompareItems,
- void* yourDataPtr,
- void* swapBuffer)
- {
- if (beginIndex < endIndex)
- {
- ArrayIndex left = QSRandomPartition(beginIndex, endIndex, CompareItems, yourDataPtr, swapBuffer);
- QuickSort(beginIndex, left, CompareItems, yourDataPtr, swapBuffer);
- QuickSort(left + 1, endIndex, CompareItems, yourDataPtr, swapBuffer);
- }
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QSPartition:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- ArrayIndex TDynamicArray::QSPartition(ArrayIndex beginIndex, // p
- ArrayIndex endIndex, // r
- CompareElementsType CompareItems,
- void* yourDataPtr,
- void* swapBuffer)
- {
- if (beginIndex >= endIndex)
- return endIndex;
- {
- void* pivot = ComputeAddress(beginIndex); // x
- ArrayIndex i = beginIndex - 1; // p - 1
- ArrayIndex j = endIndex + 1; // r + 1
- while (TRUE)
- {
- void* secondKey;
- do
- {
- --j;
- secondKey = ComputeAddress(j); // A[j]
- } while (CompareItems(pivot, secondKey, yourDataPtr) <= kItem1LessThanItem2);
-
- do
- {
- ++i;
- secondKey = ComputeAddress(i); // A[i]
- } while (CompareItems(pivot, secondKey, yourDataPtr) >= kItem1GreaterThanItem2);
-
- if (i < j)
- {
- // Swap the elements
- SwapElements(ComputeAddress(i), ComputeAddress(j), swapBuffer);
- }
- else
- return j;
- }
- }
-
- return 0; // this return statement is never executed, but exists to defeat an xlC warning
- }
-
- //----------------------------------------------------------------------------------------
- // TDynamicArray::QSRandomPartition:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- ArrayIndex TDynamicArray::QSRandomPartition(ArrayIndex beginIndex,
- // p
- ArrayIndex endIndex,
- // r
- CompareElementsType CompareItems,
- void* yourDataPtr,
- void* swapBuffer)
- {
- ArrayIndex i = RandomArrayIndex(beginIndex, endIndex);
-
- // exchange
- SwapElements(ComputeAddress(beginIndex), ComputeAddress(i), swapBuffer);
-
- return QSPartition(beginIndex, endIndex, CompareItems, yourDataPtr, swapBuffer);
- }
-
- //----------------------------------------------------------------------------------------
- // RandomArrayIndex:
- //----------------------------------------------------------------------------------------
- ArrayIndex RandomArrayIndex(ArrayIndex beginIndex,
- ArrayIndex endIndex)
- {
- if (beginIndex == endIndex)
- return beginIndex;
- ArrayIndex randomValue = rand() % labs(endIndex - beginIndex);
-
- return beginIndex + randomValue;
- }
-
- //----------------------------------------------------------------------------------------
- // CompareObjects:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- CompareResult CompareElements(void* element1,
- void* element2,
- void* yourDataPtr)
- {
- return ((TDynamicArray *)yourDataPtr)->CompareElements(element1, element2);
- }
-
-
- //========================================================================================
- // struct CElementInserter
- //========================================================================================
-
- struct CElementInserter
- {
- public:
- void*& fElementPtr;
- TSortedDynamicArray* fDynamicArray;
-
- CElementInserter(void*& theElementPtr,
- TSortedDynamicArray* theDynamicArray) :
- fElementPtr(theElementPtr),
- fDynamicArray(theDynamicArray)
- {
- }
- };
-
-
- //----------------------------------------------------------------------------------------
- // TestItemForInsert:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- CompareResult TestItemForInsert(ArrayIndex anItem,
- void* yourDataPtr)
- {
- CElementInserter * insertInfo = (CElementInserter *)yourDataPtr;
- return insertInfo->fDynamicArray->CompareElements(insertInfo->fElementPtr, insertInfo->fDynamicArray->ComputeAddress(anItem));
- }
-
-
- //========================================================================================
- // CLASS TSortedDynamicArray
- //========================================================================================
- #undef Inherited
- #define Inherited TDynamicArray
-
- #pragma segment ListNonRes
- MA_DEFINE_CLASS_M1(TSortedDynamicArray,
- Inherited);
-
- //----------------------------------------------------------------------------------------
- // TSortedDynamicArray destructor
- //----------------------------------------------------------------------------------------
- #pragma segment MADestructorRes
-
- TSortedDynamicArray::~TSortedDynamicArray()
- {
- }
-
- //----------------------------------------------------------------------------------------
- // TSortedDynamicArray::DoSearchElement: DON'T use exit to get out of this routine from
- // your TestItem function or you will be really sad! (our debugger will check for you)
- // That's why you can return true to stop enumerating. Signaling Failure is OK too.
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
-
- Boolean TSortedDynamicArray::DoSearchElement(CompareIndexType TestItem,
- void* yourDataPtr,
- ArrayIndex& index)
- {
- Boolean found = FALSE;
-
- if (fSize == kEmptyIndex)
- index = 1;
- else
- {
- CompareResult aCompareResult;
- CArrayIterator iter(this);
-
- do
- {
- // (fLowBound + fHighBound) / 2
- iter.fCurrentIndex = (iter.fLowBound + iter.fHighBound) >> 1;
-
- aCompareResult = TestItem(iter.fCurrentIndex, yourDataPtr);
-
- if (aCompareResult <= kItemGreaterThanCriteria)
- iter.fHighBound = iter.fCurrentIndex - 1;
- else
- iter.fLowBound = iter.fCurrentIndex + 1;
-
- } while (!((aCompareResult == kItemEqualCriteria) || (iter.fLowBound > iter.fHighBound)));
-
- if (aCompareResult == kItemEqualCriteria)
- found = TRUE;
- else if (aCompareResult >= kItemLessThanCriteria)
- ++iter.fCurrentIndex;
-
- // keep index in range
- index = ((iter.fCurrentIndex < 1) || (iter.fCurrentIndex > fSize + 1)) ? kEmptyIndex : iter.fCurrentIndex;
-
- }
-
- return found;
- }
-
- //----------------------------------------------------------------------------------------
- // TSortedDynamicArray::InsertElementInOrder:
- //----------------------------------------------------------------------------------------
- #pragma segment ListRes
- void TSortedDynamicArray::InsertElementInOrder(void* elementPtr)
- {
- ArrayIndex index;
- CElementInserter anElementInserter(elementPtr, this);
-
- DoSearchElement(&TestItemForInsert, &anElementInserter, index);
- InsertElementsBefore(index, elementPtr, 1);
- }
-
- //----------------------------------------------------------------------------------------
- // End of UDynamicArray.cp
-
- #pragma segment Inline
-